{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Downloading Overlays\n",
    "\n",
    "This notebook demonstrates how to download an FPGA overlay and examine programmable logic state.  \n",
    "\n",
    "## 1. Instantiating an overlay\n",
    "With the following overlay bundle present in the `overlays` folder, users can instantiate the overlay easily.\n",
    "\n",
    "*  A bitstream file (\\*.bit).\n",
    "*  A tcl file (\\*.tcl), or an hwh file (\\*.hwh).\n",
    "*  A python class (\\*.py).\n",
    "\n",
    "For example, an overlay called `base` can be loaded by:\n",
    "```python\n",
    "from pynq.overlays.base import BaseOverlay\n",
    "overlay = BaseOverlay(\"base.bit\")\n",
    "```\n",
    "Users can also use the absolute file path of the bitstream to instantiate the overlay.\n",
    "\n",
    "In this notebook, we get the current bitstream loaded on PL, and try to download it multiple times."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "\n",
       "require(['notebook/js/codecell'], function(codecell) {\n",
       "  codecell.CodeCell.options_default.highlight_modes[\n",
       "      'magic_text/x-csrc'] = {'reg':[/^%%microblaze/]};\n",
       "  Jupyter.notebook.events.one('kernel_ready.Kernel', function(){\n",
       "      Jupyter.notebook.get_cells().map(function(cell){\n",
       "          if (cell.cell_type == 'code'){ cell.auto_highlight(); } }) ;\n",
       "  });\n",
       "});\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import os, warnings\n",
    "from pynq import PL\n",
    "from pynq import Overlay\n",
    "\n",
    "if not os.path.exists(PL.bitfile_name):\n",
    "    warnings.warn('There is no overlay loaded after boot.', UserWarning)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note**: If you see a warning message in the above cell, it means that no overlay\n",
    "has been loaded after boot, hence the PL server is not aware of the \n",
    "current status of the PL. In that case you won't be able to run this notebook\n",
    "until you manually load an overlay at least once using:\n",
    "\n",
    "```python\n",
    "from pynq import Overlay\n",
    "ol = Overlay('your_overlay.bit')\n",
    "```\n",
    "\n",
    "If you do not see any warning message, you can safely proceed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "ol = Overlay(PL.bitfile_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can check the download timestamp for this overlay."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2019/8/2 18:0:15 +752992'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ol.download()\n",
    "ol.timestamp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Examining the PL state\n",
    "\n",
    "While there can be multiple overlay instances in Python, there is only one bitstream that is currently loaded onto the programmable logic (PL). \n",
    "\n",
    "This bitstream state is held in the singleton class, PL, and is available for user queries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'/usr/local/lib/python3.6/dist-packages/pynq/overlays/base/base.bit'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PL.bitfile_name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2019/8/2 18:0:15 +752992'"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "PL.timestamp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Users can verify whether an overlay instance is currently loaded using the Overlay is_loaded() method"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ol.is_loaded()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Overlay downloading overhead\n",
    "\n",
    "Finally, using Python, we can see the bitstream download time over 50 downloads.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0xadd09c90>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import time\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "length = 50\n",
    "time_log = []\n",
    "for i in range(length):\n",
    "    start = time.time()\n",
    "    ol.download()\n",
    "    end = time.time()\n",
    "    time_log.append((end-start)*1000)\n",
    "\n",
    "%matplotlib inline\n",
    "plt.plot(range(length), time_log, 'ro')\n",
    "plt.title('Bitstream loading time (ms)')\n",
    "plt.axis([0, length, 0, 1000])\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
